/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package treegenerator.gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import javax.swing.Box;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 *
 * @author jannes
 */
public class TreeXMLViewer extends JPanel{
    private Document doc;            
    private Box paramBox;
    private File file;
    private boolean changed;
    public TreeXMLViewer(){
        setLayout(new BorderLayout());        
        this.setMaximumSize(new Dimension(200,10000));
        JLabel lblTitle = new JLabel(" Arbaro Parameters ");
        lblTitle.setFont(new Font(lblTitle.getFont().getName(), Font.BOLD, 20));
        Box hb = Box.createHorizontalBox();        
        hb.add(Box.createHorizontalGlue());
        hb.add(lblTitle);
        hb.add(Box.createHorizontalGlue());
        add(hb,BorderLayout.NORTH);
        paramBox = Box.createVerticalBox();
        JScrollPane scrollPane = new JScrollPane(paramBox);
        add(scrollPane,BorderLayout.CENTER);        
    }
    
    public void readXML(File file){
        if(checkXML(file)){            
            this.file = file;
            try {    
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();      
                DocumentBuilder loader = factory.newDocumentBuilder();     
                doc = loader.parse(file);       
                changed = false;
                createTree();
           }catch (Exception ex) {
               ex.printStackTrace();
           }
           revalidate();
        }        
    }
    
    private void createTree(){
        paramBox.removeAll();                
        NodeList params = doc.getElementsByTagName("param");            
        HashMap<Integer,Box> levelBoxes = new HashMap<Integer, Box>();
        Box generalBox = Box.createVerticalBox();
        for(int i = 0; i < params.getLength(); i++){            
            Node param = params.item(i);
            String name = param.getAttributes().getNamedItem("name").getNodeValue();                    
            Character c = name.charAt(0);
            Box currentBox = null;
            if(Character.isDigit(name.charAt(0))){
                //level param                
                Integer level = Integer.parseInt(name.substring(0, 1));
                currentBox = levelBoxes.get(level);                
                if(currentBox == null){
                    Box levelBox = Box.createVerticalBox();
                    levelBoxes.put(level,levelBox);
                    currentBox = levelBox;
                }
                name = name.substring(1);
            }else{
                //general param
                currentBox = generalBox;                
            }
            Box box = Box.createHorizontalBox();
            JLabel lbl = new JLabel(name);
            JTextField txt = new LinkedTextField(param.getAttributes().getNamedItem("value"));            
            box.add(Box.createHorizontalStrut(10));
            box.add(lbl);
            box.add(Box.createHorizontalStrut(15));
            box.add(txt);       
            box.add(Box.createHorizontalStrut(20));
            currentBox.add(box);
        }
        //add general options;              
        Box box = Box.createHorizontalBox();
        box.add(new JLabel("General"));
        box.add(Box.createHorizontalGlue());
        paramBox.add(new JSeparator());
        paramBox.add(box);
        paramBox.add(new JSeparator());
        paramBox.add(generalBox);
        
        box = Box.createHorizontalBox();            
        box.add(new JLabel("Trunk"));
        box.add(Box.createHorizontalGlue());
        paramBox.add(new JSeparator());
        paramBox.add(box);            
        paramBox.add(new JSeparator());
        paramBox.add(levelBoxes.get(0));
        
        for(int i = 1; i < levelBoxes.size(); i++){            
            box = Box.createHorizontalBox();            
            box.add(new JLabel("Level: " + i));
            box.add(Box.createHorizontalGlue());
            paramBox.add(new JSeparator());
            paramBox.add(box);            
            paramBox.add(new JSeparator());
            paramBox.add(levelBoxes.get((Integer)i));
        }
    }
    
    private class LinkedTextField extends JTextField{
        private Node node;
        
        public LinkedTextField(Node node_){
            super(node_.getNodeValue());
            node = node_;
            setHorizontalAlignment(SwingConstants.TRAILING);
            addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent ae) {
                    node.setNodeValue(getText());
                    changed = true;
                }
            });            
            addFocusListener(new FocusAdapter() {

                @Override
                public void focusLost(FocusEvent fe) {
                    setText(node.getNodeValue());
                }                
            });
        }                
    }
    
    public boolean checkXML(File file){              
        SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");                        
        try{            
            URL url = getClass().getResource("/treegenerator/arbaro/tree.xsd");
            Schema schema = factory.newSchema(url);           
            Validator validator = schema.newValidator();                            
            Source source = new StreamSource(file);           
            try {
                validator.validate(source);
                return true;
            }
            catch (SAXException ex) {
                System.out.println("file is not valid because ");
                System.out.println(ex.getMessage());
                return false;
            }  
        }catch(Exception ex){
            ex.printStackTrace();
            System.out.println("can't load shema");
            return false;
        }
    }
    
    public InputStream getInputStream(){
        TransformerFactory tf = TransformerFactory.newInstance();       
        try{            
            Transformer t = tf.newTransformer();                                                    
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            t.transform(new DOMSource(doc), new StreamResult(outputStream));
            InputStream is = new ByteArrayInputStream(outputStream.toByteArray());
            return is;
        }catch(Exception exc){
            JOptionPane.showMessageDialog(null,"creating outputstream failed: " + exc);                        
        }
        return null;
    }    
    
    public void saveXML(){
        TransformerFactory tf = TransformerFactory.newInstance();       
        try{            
            Transformer t = tf.newTransformer();                                                    
            FileOutputStream fos = new FileOutputStream(file);
            t.transform(new DOMSource(doc), new StreamResult(fos));
        }catch(Exception exc){
            JOptionPane.showMessageDialog(null,"saving file failed: " + exc);            
        }        
    }
}
